#Copyright (c) 2025, Alibaba Cloud and its affiliates;
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.



import json

import fce_util.libs.localrun as localrun
import fce_util.libs.common as common
import fce_util.libs.pods as pods
import fce_util.libs.constants as constants
from fce_util.libs import log as loggers
from fce_util.fceres import fce_res_common

logger = loggers.g_logger.logger

def construct_cluster_list(clusters):
    logger.debug("clusters is {}".format(clusters))
    clusters_list = []
    for cluster in clusters:
        cluster_temp = {
            'ClusterName': cluster['NAME'],
            #'Version': cluster['VERSION'],
            #'ClusterId': cluster['NAME'],
            'Age': cluster['AGE'],
            'Status': cluster['STATUS'],
            'TotalCPUs': cluster['CPUS'],
            'TotalMemory': cluster['MEMORY'],
        }
        if 'URL' in cluster:
            cluster_temp['AccessUrl'] = cluster['URL']
        if 'AVAILABLE RESOURCES' in cluster:
            memory = cluster['AVAILABLE RESOURCES']['memory'] if 'memory' in cluster['AVAILABLE RESOURCES'] else 0
            memory_gb = common.bytes_to_gb(memory)
            cluster_temp['FreeCPUs'] = cluster['AVAILABLE RESOURCES']['CPU'] if 'CPU' in cluster['AVAILABLE RESOURCES'] else 0
            cluster_temp['FreeMemory'] = '{} GB'.format(memory_gb)
         
        clusters_list.append(cluster_temp)
    logger.debug("clusters_list is {}".format(clusters_list))

    return clusters_list

def cluster_list(args):
    """
    FCE Ray cluster list entry
    """
    #0.validate kubernetes cluster status
    logger.debug('cluster_list enter,args:{}'.format(args))
    kube_config = args.kube_config if args.kube_config else constants.KUBE_CONFIG_DEFAULT_PATH
    kubectl_bin = "kubectl --kubeconfig={} ".format(kube_config)
    logger.info("kubectl_bin is %s" % kubectl_bin)
    cmd = "{} cluster-info".format(kubectl_bin)
    status, output = localrun.run(cmd)
    if status:
        stdout = "Failed to get kubernetes cluster info, output: ()".format(output)
        logger.error(stdout)
        fce_res_common(success = False, errcode = 'InvalidParameters.ParseError', errmsg = stdout)
        return

    #1.Get Ray cluster list(total resources, with kubectl command)
    cmd = "{} get rayclusters".format(kubectl_bin)
    if args.cluster_name:
        cmd = cmd + " {}".format(args.cluster_name)
    namespace = args.namespace if args.namespace else 'default'
    cmd = cmd + " -n {}".format(namespace)      
      
    if args.cluster_id:
        logger.warning("Not supported, TBD")

    status, output = localrun.run(cmd)
    if status:
        stdout = "Failed to get ray cluster list, cmd:{}, output: {}".format(cmd, output)
        logger.error(stdout)
        fce_res_common(success = False, errcode = 'InvalidParameters.ParseError', errmsg = stdout)
        return
    
    status, clusters_result = common.convert_diagram_to_array(output)
    if not status:
        logger.error(clusters_result)
        fce_res_common(success = False, errcode = 'InvalidParameters.ParseError', errmsg = clusters_result)
        return
    
    #2.Get ray cluster list(free resources, with ray core apis）
    for cluster in clusters_result:
        head_pod = pods.get_deployment_pod(cluster['NAME'], constants.HEAD_GROUP, namespace)
        cmd = "{} exec {} -n {} -- python -c 'import ray; ray.init(); print(ray.available_resources())'".format(kubectl_bin, head_pod, namespace)
        logger.debug('cluster available_resources cmd:{}'.format(cmd))
        status, output = localrun.run(cmd)
        if status:
            stdout = "Failed to get ray cluster available resources, output: ()".format(output)
            logger.error(stdout)
            fce_res_common(success = False, errcode = 'InvalidParameters.ParseError', errmsg = stdout)
            return
        status, analyze_result = common.analyze_cluster_available_resource(output)
        if not status:
            logger.error("Failed to analyze cluster resource for cluster {}".format(cluster['NAME']))
            continue
        cluster['URL'] = analyze_result['cluster_url']
        cluster['AVAILABLE RESOURCES'] = analyze_result['resource']

    clusters_results = construct_cluster_list(clusters_result)

    msg = {'Success': True}
    msg['Message'] = {
        'TotalCount': len(clusters_results),
        'ClusterList': clusters_results
    }
    print(json.dumps(msg))

def FCE_cluster_list(args):
    if args.rayc == 'cluster_list':
        cluster_list(args)
        return
    args.this_parser.print_help()

def make(parser):
    """
    FCE Ray Cluster List entry
    """
    parser.add_argument( 
        '--cluster_name',
        dest='cluster_name',
        nargs = '?',
        metavar = ('CLUSTER_NAME'),
        help='Ray Cluster Name',
        required=False,
        )
    
    parser.add_argument( 
        '--cluster_id',
        dest='cluster_id',
        nargs = '?',
        metavar = ('CLUSTER_ID'),
        help='Ray Cluster Id',
        required=False,
        )   
    
    parser.add_argument( 
        '--cluster_version',
        dest='cluster_version',
        nargs = '?',
        metavar = ('CLUSTER_VERSION'),
        help='Ray Cluster Version',
        required=False,
        )
    
    parser.add_argument( 
        '--namespace',
        dest='namespace',
        nargs = '?',
        metavar = ('NAMESPACE'),
        help='Ray Cluster Namespace',
        required=False,
        )
    
    parser.add_argument( 
        '--kube_config',
        dest='kube_config',
        nargs = '?',
        metavar = ('KUBE_CONFIG'),
        help='Kube Config File Path',
        required=False,
        )
    
    parser.set_defaults(
        func=FCE_cluster_list,
        this_parser=parser
    )
